import os
import json
import argparse
import logging
from typing import List, Dict, Optional


def load_reference_data(reference_data_path: str) -> List[Dict[str, str]]:
    """从 JSON 配置文件中加载 REFERENCE_DATA"""
    try:
        with open(reference_data_path, "r") as f:
            return json.load(f)
    except Exception as e:
        raise ValueError(
            f"Failed to load reference data from {reference_data_path}: {e}"
        )


class OpenSourceValidator:
    def __init__(
        self, project_root: str, reference_data: List[Dict[str, str]], log_file: str
    ):
        self.project_root = project_root
        self.reference_data = reference_data
        self.log_file = log_file

        # 设置日志文件
        logging.basicConfig(
            filename=self.log_file,
            level=logging.INFO,
            format="%(asctime)s - %(levelname)s - %(message)s",
        )

    def find_all_readmes(self) -> List[str]:
        """递归查找所有 README.OpenSource 文件"""
        readme_paths = []
        for dirpath, _, filenames in os.walk(self.project_root):
            if "README.OpenSource" in filenames:
                readme_paths.append(os.path.join(dirpath, "README.OpenSource"))
        return readme_paths

    def find_reference_data(self, name: str) -> Optional[Dict[str, str]]:
        """在参考数据中根据名称查找对应的开源软件信息"""
        for reference in self.reference_data:
            if reference.get("Name") == name:
                return reference
        return None

    def validate_readme(self, readme_path: str) -> Optional[List[Dict[str, str]]]:
        """校验某个 README.OpenSource 文件的内容，并比对其字段与参考数据一致"""
        # Step 1: 读取 JSON 文件
        try:
            with open(readme_path, "r") as f:
                readme_data = json.load(f)
        except json.JSONDecodeError as e:
            logging.error(f"README.OpenSource is not a valid JSON file: {e}")
            return None

        # Step 2: 校验 JSON 数组中的每个开源软件元数据
        for software_data in readme_data:
            name = software_data.get("Name")
            reference_data = self.find_reference_data(name)

            if reference_data is None:
                logging.error(
                    f"Software '{name}' not found in reference data for {readme_path}."
                )
                continue

            # 比对 "Name", "License", "Version Number", "Upstream URL"
            for field in ["Name", "License", "Version Number", "Upstream URL"]:
                expected_value = reference_data.get(field)
                actual_value = software_data.get(field)
                if actual_value != expected_value:
                    logging.error(
                        f"Field '{field}' mismatch for {name} in {readme_path}. Expected: {expected_value}, Found: {actual_value}"
                    )
                    return None  # 校验失败，退出

            # 校验 "License File" 路径是否存在
            self.validate_license_file(readme_path, software_data.get("License File"))

        logging.info(f"Validation passed for {readme_path}")
        return readme_data

    def validate_license_file(self, readme_path: str, license_file: str) -> None:
        """校验 LICENSE 文件是否存在，路径相对于 README.OpenSource 文件所在目录"""
        if not license_file:
            logging.error(f"License file path is missing in {readme_path}.")
            return

        # README.OpenSource 文件所在的目录
        readme_dir = os.path.dirname(readme_path)
        license_file_path = os.path.join(readme_dir, license_file)

        # 检查 LICENSE 文件是否存在
        if not os.path.exists(license_file_path):
            logging.error(
                f"License file '{license_file}' not found at: {license_file_path}"
            )
        else:
            logging.info(f"License file at {license_file_path} is valid.")

    def run_validation(self):
        """运行完整的校验流程，递归处理所有 README.OpenSource 文件"""
        try:
            # Step 1: 查找所有 README.OpenSource 文件
            readme_paths = self.find_all_readmes()
            if not readme_paths:
                raise FileNotFoundError(
                    "No README.OpenSource files found in the project directory."
                )

            # Step 2: 校验每个 README.OpenSource 文件
            for readme_path in readme_paths:
                logging.info(f"Validating: {readme_path}")
                self.validate_readme(readme_path)

            logging.info("All validations completed.")

        except Exception as e:
            logging.error(f"Validation failed: {e}")


# 主程序
if __name__ == "__main__":
    parser = argparse.ArgumentParser(
        description="Validate README.OpenSource files in a project."
    )
    parser.add_argument("project_root", help="The root directory of the project.")
    parser.add_argument(
        "reference_data_path", help="Path to the reference data JSON file."
    )
    parser.add_argument("log_file", help="Path to the log file for validation results.")

    args = parser.parse_args()

    # 从配置文件中加载 REFERENCE_DATA
    reference_data = load_reference_data(args.reference_data_path)

    # 初始化验证器对象
    validator = OpenSourceValidator(args.project_root, reference_data, args.log_file)

    # 执行校验流程
    validator.run_validation()
